package com.lbh.platforms.windows;

import com.lbh.structures.components.render.IndexBuffer;
import com.lbh.structures.components.render.VertexBuffer;
import com.lbh.structures.components.render.VertexInfo;
import com.lbh.structures.components.render.vertex.*;

import static com.lbh.platforms.windows.WinOpenGL32.GL_TRIANGLES;
import static com.lbh.platforms.windows.WinOpenGL32.ins;

/***
 * project:JRuntime
 * package:com.lbh.structures.components.render
 *
 * @author user:lenovo QQ:1601078366
 * @date 2021/10/19 23:44
 * @version V1.0
 */
@SuppressWarnings("SpellCheckingInspection")
public class WinMesh {

    public static final int MESH_PRIMITIVE_CUBE = 0;

    public VertexBuffer vert;
    public IndexBuffer index;

    public WinMesh(int vertcnt){
        vert = new VertexBuffer(vertcnt);
        index = null;
    }

    public WinMesh(int vertcnt, int indexcnt){
        vert = new VertexBuffer(vertcnt);
        index = new IndexBuffer(indexcnt);
    }

    private void drawVertex(VertexInfo info){
        if (info.vertex instanceof VertexXYZ){
            VertexXYZ vertex = (VertexXYZ)info.vertex;
            ins.glVertex3f(vertex.x, vertex.y, vertex.z);
        }else if (info.vertex instanceof VertexXYZW){
            VertexXYZW vertex = (VertexXYZW)info.vertex;
            ins.glVertex4f(vertex.x, vertex.y, vertex.z, vertex.w);
        }
        if (info.color != null){
            if (info.color instanceof ColorR8G8B8){
                ColorR8G8B8 color = (ColorR8G8B8)info.color;
                ins.glColor3b(color.r, color.g, color.b);
            }else if (info.color instanceof ColorR8G8B8A8){
                ColorR8G8B8A8 color = (ColorR8G8B8A8)info.color;
                ins.glColor4b(color.r, color.g, color.b, color.a);
            }
        }
    }

    public void draw(){
        ins.glBegin(GL_TRIANGLES);
        if (index == null){
            for (VertexInfo info : vert.vertices) {
                drawVertex(info);
            }
        }else {
            for (short index : index.indexes) {
                if (index < vert.vertices.length){
                    drawVertex(vert.vertices[index]);
                }
            }
        }
        ins.glEnd();
    }

    public Vertex getVertex(int index){
        return vert.vertices[index].vertex;
    }

    public Color getColor(int index){
        return vert.vertices[index].color;
    }

    public short getIndex(int index){
        return this.index.indexes[index];
    }

    public void setVertex(int index, Vertex vertex){
        vert.vertices[index].vertex = vertex;
    }

    public void setColor(int index, Color color){
        vert.vertices[index].color = color;
    }

    public void setIndex(int index, short value){
        this.index.indexes[index] = value;
    }

    public void setIndexes(short[] values){
        for (int i = 0; i < values.length && i < this.index.indexes.length; i++) {
            this.index.indexes[i] = values[i];
        }
    }

    private static WinMesh createCube(){
        WinMesh cube = new WinMesh(8, 36);
        cube.setVertex(0, new VertexXYZ(-0.5F, -0.5F, -0.5F));
        cube.setVertex(1, new VertexXYZ(0.5F, -0.5F, -0.5F));
        cube.setVertex(2, new VertexXYZ(-0.5F, 0.5F, -0.5F));
        cube.setVertex(3, new VertexXYZ(0.5F, 0.5F, -0.5F));
        cube.setVertex(4, new VertexXYZ(-0.5F, -0.5F, 0.5F));
        cube.setVertex(5, new VertexXYZ(0.5F, -0.5F, 0.5F));
        cube.setVertex(6, new VertexXYZ(-0.5F, 0.5F, 0.5F));
        cube.setVertex(7, new VertexXYZ(0.5F, 0.5F, 0.5F));
        cube.setIndexes(new short[]{
                0, 2, 6,
                0, 6, 4,
                1, 7, 3,
                1, 5, 7,
                0, 4, 5,
                0, 5, 1,
                2, 7, 6,
                2, 3, 7,
                0, 1, 3,
                0, 3, 2,
                4, 7, 5,
                4, 6, 7,
        });
        return cube;
    }

    public static WinMesh createPrimitive(int type){
        switch (type){
            case MESH_PRIMITIVE_CUBE:
                return createCube();
            default:
                return null;
        }
    }
}
